home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / www / cgi-bin / counter.pl < prev    next >
Encoding:
Perl Script  |  1996-11-11  |  19.2 KB  |  592 lines

  1. #!/usr/sbin/perl
  2. 'di ';
  3. 'ds 00 \\"';
  4. 'ig 00 ';
  5. #
  6. # $Id: counter.pl.m,v 1.3 1996/10/29 21:28:19 murphy Exp $
  7. # Copyright (C) 1994 Daniel F. Rich (drich@corp.sgi.com)
  8. #   This program is free software; you can redistribute it and/or modify
  9. #   it under the terms of the GNU General Public License as published by
  10. #   the Free Software Foundation; either version 2, or (at your option)
  11. #   any later version.
  12. #
  13. #   This program is distributed in the hope that it will be useful,
  14. #   but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. #   GNU General Public License for more details.
  17. #
  18. # counter - increment a counter for WWW
  19. #
  20. # This program is its own manual page,  Install in man and bin.
  21. #
  22. # To install:
  23. #   1.    Change $defcounterfile below to point to the default file containing 
  24. #    the count, or run using the -f option.  This is the file that will be
  25. #    used if the counter URL is not found in the config file, or of the
  26. #    config file can't be opened.
  27. #
  28. #   2.    If you want to run the counter out of inetd, add the following lines
  29. #    to the files specified (the port in the services file, 8987, will be
  30. #    the port specified in the URL in step 5):
  31. #    /etc/services:
  32. #        counter 8987/tcp            # WWW visitor counter
  33. #    /etc/inetd.conf (or /usr/etc/inetd.conf)
  34. #        counter stream tcp nowait www /www/bin/counter counter
  35. #    The last three fields of the line above are the user to run the counter
  36. #    under (*must* have write access to the file specified by
  37. #    $defcounterfile), the path to the counter program, and the args to pass
  38. #    to the program respectively.  The first argument must be counter, and
  39. #    any other arguments may be added on after that.
  40. #   3.    If you wish to have a counter for more than one document, you will
  41. #    need to create a config file.  By default, this is named 
  42. #    'counter.conf' and is in the same directory as the counter script,
  43. #    but you can override this with the -c option.
  44. #
  45. #   4.    Test the script by running it from the command line.  If everything
  46. #    is correct, it should return an X11 bitmap containing the current 
  47. #    count.  You will want to run it with the input redirected from
  48. #    /dev/null, as it is expecting to see a document URL on standard input.
  49. #    Ex. ./counter.pl < /dev/null
  50. #    If you want to test it with a sample document name, just type something
  51. #    like:
  52. #        GET /counter.xbm HTTP/1.0
  53. #    after running the script.
  54. #
  55. #   5.    Now, to use this from your documents, just use a URL of the form:
  56. #        http://your.www.host:8987/counter.xbm
  57. #    where counter.xbm is replaced with the filenames in your config file.
  58. #    If you only wish to count a single document, the URL above should
  59. #    work fine.
  60. #
  61. # Written 3/8/94 by Dan Rich (drich@corp.sgi.com)
  62. #     Based on C code written by Frans van Hoesel (hoesel@chem.rug.nl)
  63. #
  64. # $Log: counter.pl.m,v $
  65. # Revision 1.3  1996/10/29  21:28:19  murphy
  66. # changes necessary to support forum 96 CD
  67. #
  68. # Revision 1.2  1996/04/22  13:38:28  DTjanitor
  69. # change .www references to .www_6.0
  70. #
  71. # Revision 1.1  1996/02/15  19:47:54  dave
  72. # adding in collapsed cgi-bin{int,ext,cd} files into their .m new forms
  73. #
  74. % Revision 1.6  1995/03/31  22:36:17  dave
  75. % updating files to conform to v5.0 CD
  76. %
  77. # Revision 1.4  1995/03/11  05:22:19  dave
  78. # fixed broken uncommented comment
  79. #
  80. #
  81. # Revision 1.5  1995/01/09  19:05:37  drich
  82. # Fixed a bug in the version number code.
  83. #
  84. # Revision 1.4  1995/01/06  00:42:42  drich
  85. # Added -V flag, and documentation for the '-f' option.
  86. # Also cleaned up the code so it runs with perl5.
  87. #
  88. # Revision 1.3  1994/10/25  13:31:38  drich
  89. # Fixed a socket bug, and corrected the URL where the program is available.
  90. #
  91. # Revision 1.2  1994/10/18  20:13:29  drich
  92. # Added daemon support and additional command line flags.
  93. # Also added new documentation (man page!!)
  94. #
  95. # Revision 1.1  1994/04/18  14:48:00  drich
  96. # Initial revision
  97. #
  98.  
  99. sub usage {
  100.     print STDERR "usage: $0 [-dziV] [-p port] [-f defaultcountfile | -c configfile] [-C interval] [-D level]\n";
  101.     exit 1;
  102. }
  103.  
  104. $userName = $ENV{'USER'};
  105. print $userName;
  106. $userName = "/usr/people/guest";
  107.  
  108.  
  109. #####################################
  110. # Setup/Define Machine-Specific stuff
  111. # reference the envariable DOCUMENT_ROOT directly
  112. # contents equal to the equivalent-on-your-machine of everything *inside*
  113. # the # single, "'", quotes:  '$DocumentRoot="/AbsPath/to/your/DocRoot"'
  114. # AND have it's path from the root directory of "/" be whatever makes
  115. # sense for you on your server machine--we originally put it in
  116. # /usr/tmp but this became unreliable since /usr/tmp/ IS "fair game"
  117. # for being completely cleaned out at any time.
  118. $DocumentRoot=$ENV{'DOCUMENT_ROOT'};
  119. $DocumentRoot="/usr/netsite-docs" unless $DocumentRoot;
  120.  
  121.  
  122. $defcounterfile = "$DocumentRoot/toolbox/www/misc/counter.txt";    # Default file containing the count
  123. $defport = 8987;        # Default port to run on (standalone)
  124. ($dirname,$basename) = ($0 =~ /^(.*)\/([^\/]*)$/);
  125. if (! $basename) {
  126.     $dirname=".";
  127.     $basename=$0;
  128. }
  129. $configfile = "$dirname/counter.conf";
  130.  
  131. sub debug_print {
  132.     local($level,$message) = @_;
  133.  
  134.     return    if (!defined($debug));
  135.     return      if ($level > $debug);
  136.     $message =~ s/\n(.)/\nDEBUG:$level:$1/g     if ($message =~ /\n./);
  137.     if ($nocr && ($olevel == $level)) {
  138.         print STDERR "$message" if ($level <= $debug);
  139.     } else {
  140.         print STDERR "\n"       if ($nocr);
  141.         print STDERR "DEBUG:$level:$message";
  142.     }
  143.     $olevel = $level;
  144.     $nocr = $message !~ /\n/;
  145. }
  146.  
  147. # Read in configuration file
  148. sub read_config {
  149.     local($sig) = @_;
  150.  
  151.     if ($sig eq 'HUP') {
  152.     &debug_print(1,"Caught a SIG $sig--reloading config file\n");
  153.     &syslog('info',"Caught a SIG $sig--reloading config file") && defined($syslog);
  154.     }
  155.  
  156.     @config=();
  157.     if ( -f "$configfile" ) {
  158.     &debug_print(1, "Reading config file: $configfile...");
  159.     open(CONFIG,"<$configfile") || &syslog('err',"err opening $configfile: $!");
  160.     while (<CONFIG>) {
  161.         chop;
  162.         s/#.*$//;
  163.         next    if (!$_);
  164.         ($url,$counter,$options) = split(/\s+/,$_,3);
  165.         $config{$url} = $counter;
  166.         $options{$url} = $options;
  167.         &debug_print(2,"    $url --> $counter");
  168.         &debug_print(2,"  w/zeros")        if ($options{$url} =~ /zero/);
  169.         &debug_print(2,"  inverse")        if ($options{$url} =~ /inverse/);
  170.         &debug_print(2,"\n");
  171.     }
  172.     close(CONFIG);
  173.     &debug_print(1, "done.\n");
  174.     }
  175.     $SIG{'HUP'} = 'read_config';
  176. }
  177.  
  178. sub give_up {
  179.     print STDERR "$_[0]\n";
  180.     &syslog('warning',"$_[0]\n")        if ($syslog);
  181.     exit 1;
  182. }
  183.  
  184. push(@INC,'/usr/local/lib/perl');
  185. require('getopts.pl') || &give_up("$0: can\'t do getopts.pl: $@");
  186. require('sys/file.ph') || &give_up("$0: can\'t do sys/file.ph: $@");
  187. require('sys/errno.ph') || &give_up("$0: can\'t do sys/errno.ph: $@");
  188. undef($syslog);            # True if we can use syslog
  189. require('syslog.pl') && ($syslog = 1);
  190.  
  191. if ( ! &Getopts('c:C:dD:f:ip:Vz') ) {
  192.     &usage;
  193. }
  194. $checkpoint = $opt_C;        # Checkpoint interval
  195. $daemon = $opt_d;        # Run as a daemon? (standalone)
  196. $debug = $opt_D;
  197. # Counter file name is specified by -f or the config file (-c)
  198. $defcounterfile = $opt_f            if ($opt_f);
  199. $definverse = $opt_i;        # Invert bitmap if true
  200. $port = $opt_p ? $opt_p : $defport; # Port to run on (standalone)
  201. $defleading_zero = $opt_z;    # Print leading zeros on count
  202.  
  203. # Print version info
  204. $version="\$Revision: 1.3 $_";
  205. $version =~ s/\$Revision: 1.3 $/\1/; # Strip the RCS version
  206. if ($debug || $opt_V) {
  207.     print STDERR "WWW counter, version $version\n\n";
  208.  
  209.     if (!$debug) {
  210.     print STDERR "\$RCSfile: counter.pl.m,v $ \$Revision: 1.3 $ \$Date: 1996/10/29 21:28:19 $ \n\n";
  211.  
  212.     print STDERR "Copyright (C) 1994 Daniel F. Rich (drich\@corp.sgi.com)\n\n";
  213.     
  214.     print STDERR "This program is free software; you can redistribute it and/or modify\n";
  215.     print STDERR "it under the terms of the GNU General Public License as published by\n";
  216.     print STDERR "the Free Software Foundation; either version 2, or (at your option)\n";
  217.     print STDERR "any later version.\n\n";
  218.     
  219.     print STDERR "This program is distributed in the hope that it will be useful,\n";
  220.     print STDERR "but WITHOUT ANY WARRANTY; without even the implied warranty of\n";
  221.     print STDERR "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n";
  222.     print STDERR "GNU General Public License for more details.\n";
  223.     }
  224. }
  225. exit    if ($opt_V);
  226.  
  227. # Check for valid arguments
  228. if ($checkpoint && ($checkpoint !~ /^\d+$/)) {
  229.     &usage;
  230. }
  231. if ($port && ($port !~ /^\d+$/)) {
  232.     &usage;
  233. }
  234.  
  235. &debug_print(1, "We have syslog!!\n")        if ($syslog);
  236. &openlog($basename,'cons,pid','daemon');
  237.  
  238. &read_config(0);
  239.  
  240. # Start up the daemon if needed
  241. if ($daemon) {
  242.     if (!$debug) {
  243.     # Fork off, so we are a true deamon!
  244.     unless (fork) {
  245.         unless (fork) {
  246.         sleep 1 until getppid == 1;
  247.         if ( -e "/dev/console" ) {
  248.             close(STDERR);
  249.             open(STDERR,"> /dev/console");
  250.         }
  251.         } else {
  252.         exit 0;
  253.         }
  254.     } else {
  255.         wait;
  256.         exit 0;
  257.     }
  258.     }
  259.  
  260.     close(STDIN);        # We will map this to our socket
  261.     close(STDOUT);
  262.  
  263.     require('sys/socket.ph') || &give_up("$0: can\'t do sys/socket.ph: $@");
  264.  
  265.     $sockaddr = 'S n a4 x8';
  266.     $proto = (getprotobyname('tcp'))[2];
  267.     $this = pack($sockaddr, &AF_INET, $port, "\0\0\0\0");
  268.     select(NS); $| = 1; select(stdout);
  269.  
  270.     socket(S, &AF_INET, &SOCK_STREAM, $proto) || &give_up("socket: $!");
  271.     bind(S,$this) || &give_up("bind: $!");
  272.     listen(S,5) || &give_up("connect: $!");
  273.  
  274.     select(S); $| = 1; select(stdout);
  275.  
  276.     &syslog('notice',"daemon started on port $port");
  277. }
  278.  
  279. # bitmap for each digit
  280. @digits = (0x00,0x00,0x00,0x3c,0x66,0x66,0x66,0x66,
  281.        0x66,0x66,0x66,0x66,0x3c,0x00,0x00,0x00,
  282.        0x00,0x00,0x00,0x30,0x38,0x30,0x30,0x30,
  283.        0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x00,
  284.        0x00,0x00,0x00,0x3c,0x66,0x60,0x60,0x30,
  285.        0x18,0x0c,0x06,0x06,0x7e,0x00,0x00,0x00,
  286.        0x00,0x00,0x00,0x3c,0x66,0x60,0x60,0x38,
  287.        0x60,0x60,0x60,0x66,0x3c,0x00,0x00,0x00,
  288.        0x00,0x00,0x00,0x30,0x30,0x38,0x38,0x34,
  289.        0x34,0x32,0x7e,0x30,0x78,0x00,0x00,0x00,
  290.        0x00,0x00,0x00,0x7e,0x06,0x06,0x06,0x3e,
  291.        0x60,0x60,0x60,0x66,0x3c,0x00,0x00,0x00,
  292.        0x00,0x00,0x00,0x38,0x0c,0x06,0x06,0x3e,
  293.        0x66,0x66,0x66,0x66,0x3c,0x00,0x00,0x00,
  294.        0x00,0x00,0x00,0x7e,0x66,0x60,0x60,0x30,
  295.        0x30,0x18,0x18,0x0c,0x0c,0x00,0x00,0x00,
  296.        0x00,0x00,0x00,0x3c,0x66,0x66,0x66,0x3c,
  297.        0x66,0x66,0x66,0x66,0x3c,0x00,0x00,0x00,
  298.        0x00,0x00,0x00,0x3c,0x66,0x66,0x66,0x66,
  299.        0x7c,0x60,0x60,0x30,0x1c,0x00,0x00,0x00
  300.        );
  301.  
  302. $notdone = 1;
  303. while ($notdone) {        # Setup loop for daemon
  304.     # Wait for connection...
  305.     if ($daemon) {
  306.     &debug_print(1,"Waiting for connection...\n");
  307.     while (!accept(NS,S)) { # Restart if EINTR
  308.         &give_up("accept: $!")    if ($! != &EINTR);
  309.     }
  310.     open(STDOUT,">&NS");    # Map STDIN and STDOUT to the socket
  311.     open(STDIN,"<&NS");
  312.     }
  313.  
  314.     # Get URL and set counterfile
  315.     $line=<STDIN>;
  316.     ($counterurl) = ($line =~ /GET (.*) HTTP/);
  317.     $counterfile = defined($config{$counterurl}) ?
  318.     $config{$counterurl} : $defcounterfile;
  319.     $leading_zero = defined($options{$counterurl}) ?
  320.     ($options{$counterurl} =~ /zero/) : $defleading_zero;
  321.     $inverse = defined $options{$counterurl} ? 
  322.     ($options{$counterurl} =~ /inverse/) : $definverse;
  323.     &debug_print(1,"url: $counterurl");
  324.     &debug_print(1," w/zero")        if ($leading_zero);
  325.     &debug_print(1,"\n");
  326.  
  327.     # Read and increment the counter file
  328.     while (-f "${counterfile}.lock") { sleep 1 }
  329.     open(LOCK,">${counterfile}.lock");
  330.     close(LOCK);
  331.     # If counter file exists use it, otherwise create a new one
  332.     if (-f "$counterfile" ) {
  333.     open(COUNTERFILE,"<$counterfile") ||
  334.         &give_up("$0: can\'t open $counterfile: $!\n");
  335. #        flock(COUNTERFILE,&LOCK_EX) ||
  336. #        &give_up("$0: can\'t lock $counterfile: $!\n");
  337.     $text = <COUNTERFILE>;
  338.     close(COUNTERFILE);
  339.     } else {
  340.     $text = '0';
  341.     }
  342.  
  343.     $text++;
  344.     $len = length($text) > 7 ? length($text) : 7;
  345.     open(COUNTERFILE,">$counterfile") ||
  346.     &give_up("$0: can\'t open $counterfile: $!\n");
  347.     printf COUNTERFILE "%${len}u\n",$text;
  348.     if ($leading_zero) {
  349.     $text = sprintf("%0${len}u",$text);
  350.     } else {
  351.     $len = length($text);
  352.     $text = sprintf("%${len}u",$text);
  353.     }
  354.     &debug_print(1,"count: $text\n");
  355. #    flock(COUNTERFILE,&LOCK_UN);
  356.     close(COUNTERFILE);
  357.     if ($checkpoint && ($text % $checkpoint == 0)) {
  358.     if ($syslog) {
  359.         &syslog('info',"$counterurl checkpoint: $text");
  360.     } else {
  361.         open(CHECKFILE,">${counterfile}.check") || 
  362.         warn "$0: can\'t open ${counterfile}.check: $!\n";
  363.         print CHECKFILE "%0${len}u\n",$text;
  364.         close(CHECKFILE);
  365.     }
  366.     }
  367.     unlink("${counterfile}.lock");
  368.  
  369.     # Generate an X11 bitmap on STDOUT
  370.     printf STDOUT "#define count_width %d\n#define count_height 16\n", $len*8;
  371.     printf STDOUT "static char count_bits[] = {\n";
  372.     for ($y=0; $y < 16; $y++) {
  373.     for ($x=0; $x < $len; $x++) {
  374.         $d = substr($text,$x,1) - '0';
  375.         print STDOUT '0x';
  376.         if ($inverse) {
  377.         printf STDOUT "%1x",(($digits[($d * 16) + $y] >> 4) ^ 0xf) & 0xf;
  378.         printf STDOUT "%1x",($digits[($d * 16) + $y] ^ 0xf) & 0xf;
  379.         } else {
  380.         printf STDOUT "%1x",($digits[($d * 16) + $y] >> 4) & 0xf;
  381.         printf STDOUT "%1x",$digits[($d * 16) + $y] & 0xf;
  382.         }
  383.         if ($x < $len-1) {
  384.         print STDOUT ',';
  385.         }
  386.     }
  387.     if ($y==15) {
  388.         print STDOUT '};';
  389.     } else {
  390.         print STDOUT ',';
  391.     }
  392.     print STDOUT "\n";
  393.     }
  394.     if ($daemon) {
  395.     close(STDOUT);
  396.     close(STDIN);
  397.     close(NS);
  398.     } else {
  399.     undef($notdone);
  400.     }
  401. }
  402.     
  403. ################### BEGIN PERL/TROFF TRANSITION 
  404. .00 ;    
  405.  
  406. 'di
  407. .nr nl 0-1
  408. .nr % 0
  409. '; __END__ ############## END PERL/TROFF TRANSITION
  410. .TH counter 1 "October 14, 1994"
  411. .SH NAME
  412. counter \- display a user counter for a World Wide Web document
  413. .SH SYNOPSIS
  414. .B counter 
  415. [
  416. .I -dizV
  417. ] [
  418. .I -C interval
  419. ] [
  420. .I -D debuglevel
  421. ] [
  422. .I -f defaultcounterfile
  423. |
  424. .I -c configfile
  425. ] [
  426. .I -i
  427. ] [
  428. .I -p portnum
  429. ]
  430. .SH DESCRIPTION
  431. .B counter
  432. will display a count of users accessing a World Wide Web document.
  433. .LP
  434. The output of 
  435. .B counter
  436. contains an x-bitmap of the current value stored in the counterfile.
  437. This can be used to count the number of accesses to a WWW document, by using
  438. the WWW browser's caching of image files (and therefore they
  439. won't request the image a second time).
  440. .LP
  441. .SH OPTIONS
  442. .TP
  443. .BI \-c file
  444. overrides the default config file \fIcounter.conf\fP.  The config file 
  445. specifies what file should be used to store the count for each URL that is to
  446. be counted.  It contains one line for each counter, and each line is of the
  447. form:
  448. .nf
  449. .in +5
  450. .B URLfile        counterfile    options
  451. .in -5
  452. .fi
  453. \fBURLfile\fP contains just the filename from the counter bitmap URL (with a
  454. leading slash).
  455. The only \fBoptions\fP currently supported are \fIzero\fP and \fIinverse\fP.
  456. Ex.
  457. .nf
  458. .in +5
  459. .B /counter.xbm        /www/counter.txt    zero inverse
  460. .B /counter-home.xbm    /www/counter-home.txt
  461. .in -5
  462. .fi
  463. .TP
  464. .BI \-C checkpoint
  465. causes \fBcounter\fP to checkpoint the count at the interval specified.
  466. This will be done using syslog if available, otherwise, a counterfile is
  467. created with \fI.count\fP appended to the name.
  468. .TP
  469. .B \-d
  470. will cause counter to detach itself from the controlling terminal and
  471. run as a network daemon on the port specified by the \fI-p\fP flag.  This
  472. will also cause any error messages to be output to the console.  If the
  473. \fI-D\fP option is also used, the program will not detach itself from the
  474. terminal, but will instead output the debugging information to stderr.
  475. .TP
  476. .BI \-D level
  477. enables debugging at the level specified.
  478. .TP
  479. .B \-f file
  480. specifies the counter file to use if either an unknown bitmap is specified,
  481. or if the config file cannot be opened.
  482. .TP
  483. .B \-i
  484. causes \fBcounter\fP to output an inverted bitmap (white numbers on a black
  485. background).  This affects only the default counter if a config file is used.
  486. .TP
  487. .BI \-p port
  488. specifies the port number for the daemon to run on.
  489. .TP
  490. .B \-V
  491. will print the version number of the counter script and exit.
  492. .TP
  493. .B \-z
  494. forces \fBcounter\fP to print leading zeros on the counter.  This affects only
  495. the default counter if a config file is used.
  496. .SH INSTALLATION
  497. First you need to decide if you want to run the counter from inetd, or as a
  498. standalone daemon.  You can only run from inetd if you have the ability to
  499. edit system files and restart the inetd daemon.  However, if you are going
  500. to run the counter with a config file, it will run faster if you run it as
  501. a standalone daemon (from inetd, it must reread the config file every
  502. time the counter is accessed).
  503. .LP
  504. If you are going to run it out of inetd, you need to change two of your
  505. network configuration files.  You will need to add the following line to
  506. /etc/services (the 8987 is the port number that will be specified in the 
  507. URL that accesses the counter):
  508. .nf
  509. .in +5
  510. .B counter 8987/tcp
  511. .in -5
  512. .fi
  513. and add the following to /etc/inetd.conf:
  514. .nf
  515. .in +5
  516. .B counter stream tcp nowait www /www/bin/counter counter
  517. .in -5
  518. .fi
  519. \fIWww\fP must be changed to a user who has write access to the counter files.
  520. The \fI/www/bin/counter\fP path needs to be changed to where you 
  521. installed this program, and you can add any of the options above to the 
  522. end of the line as they will be passed to the \fBcounter\fP script
  523. (NOTE: you cannot use \fI-p\fP or \fI-d\fP if running from inetd).
  524. .LP
  525. If you wish to use the counter in more than one document, you either need to 
  526. run multiple copies of this script on different ports, or use a config file
  527. as specified above.  By default, this file is named \fIcounter.conf\fP, and
  528. is located in the same directory as \fBcounter\fP.  This can be overridden
  529. with the \fI-c\fP option.
  530. .LP
  531. At this point, you are ready to test the script by running it from the
  532. command line.  You will need to redirect STDIN to /dev/null, as that is where
  533. \fBcounter\fP expects to see the document URL.  It should return an X11
  534. bitmap of the current value in the default counter file.  If you want to test
  535. \fBcounter\fP with one of the URLs in the config file, you need to pass the
  536. following as input to \fBcounter\fP (it will pause after you start it):
  537. .nf
  538. .in +5
  539. GET /counter.xbm HTTP/1.0
  540. .in -5
  541. .fi
  542. replacing /counter.xbm with the file you want to test from \fIcounter.conf\fP.
  543. .LP
  544. To get this count into your documents, use a URL of the form:
  545. .in +5
  546. .I http://your.server.host:8987/counter.xbm
  547. .in -5
  548. where \fI8987\fP is the port \fBcounter\fP is running on, and counter.xbm is
  549. one of the names in your config file.
  550. .SH FILES
  551. .TP
  552. .B counter.txt
  553. default file which holds the user count
  554. .TP
  555. .B counter.txt.lock
  556. default lock file used to enforce file locking
  557. .TP
  558. .B counter.conf
  559. default counter configuration file
  560. .TP
  561. .B /etc/inted.conf
  562. .TP
  563. .B /etc/services
  564. .SH SEE ALSO
  565. \fBsyslog\fP(3), \fBperl\fP.
  566. .SH BUGS
  567. .LP
  568. The one known problem with \fBcounter\fP is that it will occasionally
  569. zero the count file under heavy loads.  I believe this is caused by a race
  570. condition with the lock files, but have never been able to track it down.
  571. That is the main reason the checkpoint option was added to this version 
  572. of \fBcounter\fP.
  573. .SH CREDITS
  574. Frans van Hoesel (hoesel@chem.rug.nl) originaly wrote a simple 
  575. C counter that I ported to perl.  While his program was a perfectly
  576. good solution to the counting problem, I wanted a version written in
  577. perl that would be easier for me to maintain and modify.
  578. .LP
  579. Since then, it has had a slight case of creeping-featurism, and
  580. now contains several command line flags, a config file, and a man page.
  581. .SH AVAILABILITY
  582. The latest version of 
  583. .B counter
  584. is available through SGI's Silicon Surf WWW site at
  585. .IR http://www.sgi.com/counter.html.  
  586. Just select the counter for a description of the program, and an option
  587. to download the latest version of this script.
  588. .SH AUTHOR
  589. .I Daniel Rich\ \ \ \ <drich@corp.sgi.com>
  590.